<template>
  <div class="neo4j-graph-container">
    <!-- <div class="controls">
          <button @click="resetView">重置视图</button>
          <button @click="runQuery">重新查询</button>
        </div> -->

    <div class="main-content">
      <div class="query-info">
        <div class="legend">
          <h3>图例</h3>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #68d391"></div>
            <span>起始IP</span>
          </div>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #f6ad55"></div>
            <span>IP段 (IpC)</span>
          </div>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #4fd1c5"></div>
            <span>Landmark IP</span>
          </div>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #fc8181"></div>
            <span>组织 (Org)</span>
          </div>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #9ae6b4"></div>
            <span>标题 (Title)</span>
          </div>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #fbb6ce"></div>
            <span>主机端口 (HostPort)</span>
          </div>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #90cdf4"></div>
            <span>邮箱 (Email)</span>
          </div>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #d53f8c"></div>
            <span>BELONGS_TO关系</span>
          </div>
          <div class="legend-item">
            <div class="legend-color" style="background-color: #9f7aea"></div>
            <span>其他关系</span>
          </div>
        </div>

        <div class="node-info">
          <h3>统计信息</h3>
          <div class="node-stats">
            <div class="stat-item">
              <label>节点总数</label>
              <span>{{ totalNodes }}</span>
            </div>
            <div class="stat-item">
              <label>关系总数</label>
              <span>{{ totalRelationships }}</span>
            </div>
            <div class="stat-item">
              <label>路径长度</label>
              <span>{{ pathLength }}</span>
            </div>
            <div class="stat-item">
              <label>组织数量</label>
              <span>{{ orgCount }}</span>
            </div>
          </div>
        </div>
      </div>

      <div  class="graph-container">
        <svg ref="graph" width="100%" height="100%"></svg>

        <div v-if="showBootm" class="details-panel" :class="{ expanded: detailsExpanded }">
          <div class="details-header">
            <h3>节点详情</h3>
            <!-- <button class="toggle-details" @click="toggleDetails">
              {{ detailsExpanded ? "−" : "+" }}
            </button> -->
          </div>
          <div class="details-content" ref="detailsContent">
            <!-- 动态填充详情 -->
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import * as d3 from "d3";

export default {
  name: "Graph3",
  props: {
    graphData: {
      type: Array,
      required: true,
      default: () => [],
    },
    showBootm: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      svg: null,
      g: null,
      zoom: null,
      simulation: null,
      graphDataProcessed: {
        nodes: [],
        links: [],
      },
      totalNodes: 0,
      totalRelationships: 0,
      pathLength: 0,
      orgCount: 0,
      detailsExpanded: false,
    };
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart();
      this.processData();
    });

    // 监听窗口大小变化
    window.addEventListener("resize", this.handleResize);
  },
  watch: {
    graphData: {
      handler(newVal) {
        if (newVal && newVal.length > 0) {
          this.processData();
        }else{
          this.graphDataProcessed.nodes = [];
          this.graphDataProcessed.links = [];
          this.totalNodes = 0;
          this.totalRelationships = 0;
          this.orgCount = 0;
          this.pathLength = 0;
         //清空图
         this.g.selectAll("*").remove();
        }
      },
      deep: true,
    },
  },
  methods: {
    handleResize() {
      if (this.svg) {
        const width = this.svg.node().parentElement.clientWidth;
        const height = this.svg.node().parentElement.clientHeight;
        this.svg.attr("width", width).attr("height", height);
      }
    },

    initChart() {
      this.svg = d3.select(this.$refs.graph);
      const width = this.svg.node().parentElement.clientWidth;
      const height = this.svg.node().parentElement.clientHeight;

      // 设置SVG尺寸
      this.svg.attr("width", width).attr("height", height);

      // 创建缩放和平移行为
      this.zoom = d3
        .zoom()
        .scaleExtent([0.1, 4])
        .on("zoom", (event) => {
          this.g.attr("transform", event.transform);
        });

      this.svg.call(this.zoom);

      // 创建分组用于存放所有图形元素
      this.g = this.svg.append("g");
    },

    processData() {
      if (
        !this.graphData ||
        !Array.isArray(this.graphData) ||
        this.graphData.length === 0
      ) {
        console.warn("Graph data is empty or invalid");
        return;
      }

      // 清空现有数据
      this.graphDataProcessed.nodes = [];
      this.graphDataProcessed.links = [];

      // 用于去重的节点映射
      const nodeMap = new Map();
      const linkMap = new Map();

      // 处理每个查询结果
      this.graphData.forEach((result, resultIndex) => {
        // 添加起始IP节点
        if (result.start_ip) {
          const startIpId = `start_ip_${result.start_ip.id}`;
          if (!nodeMap.has(startIpId)) {
            nodeMap.set(startIpId, {
              id: startIpId,
              label: "Ip",
              name: result.start_ip.address || "起始IP",
              type: "start_ip",
              originalData: result.start_ip,
            });
          }
        }

        // 添加IPC节点
        if (result.ipc) {
          const ipcId = `ipc_${result.ipc.id}`;
          if (!nodeMap.has(ipcId)) {
            nodeMap.set(ipcId, {
              id: ipcId,
              label: "IpC",
              name: result.ipc.name || "IP段",
              type: "ipc",
              originalData: result.ipc,
            });
          }
        }

        // 处理路径中的所有节点
        if (result.all_nodes_in_path) {
          result.all_nodes_in_path.forEach((node, nodeIndex) => {
            const nodeId = `${node.labels[0]}_${node.id}`;
            if (!nodeMap.has(nodeId)) {
              let nodeType = "other";
              let displayName = "";

              // 根据标签确定节点类型和显示名称
              if (node.labels.includes("Ip")) {
                nodeType = "landmark_ip";
                displayName = node.value.Ip || "Landmark IP";
              } else if (node.labels.includes("HostPort")) {
                nodeType = "hostport";
                displayName = node.value.HostPortId || "HostPort";
              } else if (node.labels.includes("Title")) {
                nodeType = "title";
                displayName = node.value.Title || "Title";
              } else if (node.labels.includes("Org")) {
                nodeType = "org";
                displayName = node.value.name || "Organization";
              } else if (node.labels.includes("Email")) {
                nodeType = "email";
                displayName = node.value.Email || "Email";
              }

              nodeMap.set(nodeId, {
                id: nodeId,
                label: node.labels[0],
                name: displayName,
                type: nodeType,
                originalData: node.value,
              });
            }
          });
        }

        // 处理关系
        if (result.all_relationships_in_path) {
          result.all_relationships_in_path.forEach((rel, relIndex) => {
            // 找到对应的节点ID
            let sourceNodeId = null;
            let targetNodeId = null;

            // 根据关系找到源节点和目标节点
            if (result.all_nodes_in_path) {
              const sourceNode = result.all_nodes_in_path.find(
                (n) => n.id === rel.start
              );
              const targetNode = result.all_nodes_in_path.find(
                (n) => n.id === rel.end
              );

              if (sourceNode && targetNode) {
                sourceNodeId = `${sourceNode.labels[0]}_${sourceNode.id}`;
                targetNodeId = `${targetNode.labels[0]}_${targetNode.id}`;
              }
            }

            // 添加起始IP到IPC的关系
            if (result.start_ip && result.ipc) {
              const startIpId = `start_ip_${result.start_ip.id}`;
              const ipcId = `ipc_${result.ipc.id}`;
              const linkId = `link_start_ip_${result.start_ip.id}_to_ipc_${result.ipc.id}`;

              if (!linkMap.has(linkId)) {
                linkMap.set(linkId, {
                  source: startIpId,
                  target: ipcId,
                  type: "BELONGS_TO",
                  relation: "BELONGS_TO",
                });
              }
            }

            // 添加IPC到Landmark IP的关系
            if (result.ipc && result.all_nodes_in_path) {
              const landmarkNode = result.all_nodes_in_path.find(
                (n) => n.labels.includes("Ip") && n.value.landmark_node === 1
              );

              if (landmarkNode) {
                const ipcId = `ipc_${result.ipc.id}`;
                const landmarkId = `${landmarkNode.labels[0]}_${landmarkNode.id}`;
                const linkId = `link_ipc_${result.ipc.id}_to_landmark_${landmarkNode.id}`;

                if (!linkMap.has(linkId)) {
                  linkMap.set(linkId, {
                    source: ipcId,
                    target: landmarkId,
                    type: "BELONGS_TO",
                    relation: "BELONGS_TO",
                  });
                }
              }
            }

            // 添加路径中的关系
            if (sourceNodeId && targetNodeId) {
              const linkId = `link_${sourceNodeId}_to_${targetNodeId}`;
              if (!linkMap.has(linkId)) {
                linkMap.set(linkId, {
                  source: sourceNodeId,
                  target: targetNodeId,
                  type: rel.type,
                  relation: rel.type,
                });
              }
            }
          });
        }
      });

      // 将Map转换为数组
      this.graphDataProcessed.nodes = Array.from(nodeMap.values());
      this.graphDataProcessed.links = Array.from(linkMap.values());

      // 更新统计信息
      this.updateStatistics();

      // 重新创建可视化
      this.createVisualization();
    },

    updateStatistics() {
      this.totalNodes = this.graphDataProcessed.nodes.length;
      this.totalRelationships = this.graphDataProcessed.links.length;
      this.orgCount = this.graphDataProcessed.nodes.filter(
        (n) => n.type === "org"
      ).length;

      // 计算平均路径长度
      this.pathLength =
        this.graphDataProcessed.links.length > 0
          ? Math.round(
              (this.graphDataProcessed.links.length /
                this.graphDataProcessed.nodes.length) *
                2
            )
          : 0;
    },

    createVisualization() {
      if (!this.g) return;

      // 清空现有图形
      this.g.selectAll("*").remove();

      // 重新创建箭头定义
      this.svg.select("defs").remove();
      this.svg
        .append("defs")
        .selectAll("marker")
        .data(["belongsTo", "other"])
        .enter()
        .append("marker")
        .attr("id", (d) => d)
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 25)
        .attr("refY", 0)
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("path")
        .attr("d", "M0,-5L10,0L0,5")
        .attr("fill", (d) => (d === "belongsTo" ? "#d53f8c" : "#9f7aea"));

      // 设置颜色映射
      const colorScale = d3
        .scaleOrdinal()
        .domain([
          "start_ip",
          "ipc",
          "landmark_ip",
          "org",
          "title",
          "hostport",
          "email",
          "other",
        ])
        .range([
          "#68d391",
          "#f6ad55",
          "#4fd1c5",
          "#fc8181",
          "#9ae6b4",
          "#fbb6ce",
          "#90cdf4",
          "#d1d5db",
        ]);

      const width = this.svg.node().parentElement.clientWidth;
      const height = this.svg.node().parentElement.clientHeight;

      // 创建力导向图模拟
      this.simulation = d3
        .forceSimulation(this.graphDataProcessed.nodes)
        .force(
          "link",
          d3
            .forceLink(this.graphDataProcessed.links)
            .id((d) => d.id)
            .distance(120)
        )
        .force("charge", d3.forceManyBody().strength(-400))
        .force("center", d3.forceCenter(width / 2, height / 2))
        .force("collision", d3.forceCollide().radius(50));

      // 绘制连线
      const link = this.g
        .append("g")
        .selectAll("line")
        .data(this.graphDataProcessed.links)
        .enter()
        .append("line")
        .attr("stroke", (d) =>
          d.type === "BELONGS_TO" ? "#d53f8c" : "#9f7aea"
        )
        .attr("stroke-width", 2)
        .attr("marker-end", (d) =>
          d.type === "BELONGS_TO" ? "url(#belongsTo)" : "url(#other)"
        );

      // 绘制节点
      const node = this.g
        .append("g")
        .selectAll("circle")
        .data(this.graphDataProcessed.nodes)
        .enter()
        .append("circle")
        .attr("r", (d) => {
          // 根据节点类型设置不同大小
          if (d.type === "start_ip") return 25;
          if (d.type === "ipc") return 30;
          if (d.type === "landmark_ip") return 25;
          if (d.type === "org") return 28;
          return 20;
        })
        .attr("fill", (d) => colorScale(d.type))
        .attr("stroke", "#fff")
        .attr("stroke-width", 2)
        .call(
          d3
            .drag()
            .on("start", this.dragstarted)
            .on("drag", this.dragged)
            .on("end", this.dragended)
        )
        .on("click", (event, d) => {
          this.showNodeDetails(d);
        });

      // 添加节点标签
      const label = this.g
        .append("g")
        .selectAll("text")
        .data(this.graphDataProcessed.nodes)
        .enter()
        .append("text")
        .text((d) =>
          d.name.length > 15 ? d.name.substring(0, 15) + "..." : d.name
        )
        .attr("text-anchor", "middle")
        .attr("dy", (d) => {
          // 根据节点大小调整标签位置
          if (d.type === "start_ip") return -30;
          if (d.type === "ipc") return -35;
          if (d.type === "landmark_ip") return -30;
          if (d.type === "org") return -33;
          return -25;
        })
        .attr("fill", "white")
        .attr("font-size", 11);

      // 添加关系标签
      const linkLabel = this.g
        .append("g")
        .selectAll("text")
        .data(this.graphDataProcessed.links)
        .enter()
        .append("text")
        .text((d) =>
          d.relation.length > 10
            ? d.relation.substring(0, 10) + "..."
            : d.relation
        )
        .attr("fill", "white")
        .attr("font-size", 9)
        .attr("text-anchor", "middle");

      // 力导向图模拟tick事件
      this.simulation.on("tick", () => {
        link
          .attr("x1", (d) => d.source.x)
          .attr("y1", (d) => d.source.y)
          .attr("x2", (d) => d.target.x)
          .attr("y2", (d) => d.target.y);

        node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);

        label.attr("x", (d) => d.x).attr("y", (d) => d.y);

        linkLabel
          .attr("x", (d) => (d.source.x + d.target.x) / 2)
          .attr("y", (d) => (d.source.y + d.target.y) / 2);
      });
    },

    // 拖拽函数
    dragstarted(event, d) {
      if (!event.active) this.simulation.alphaTarget(0.3).restart();
      d.fx = d.x;
      d.fy = d.y;
    },

    dragged(event, d) {
      d.fx = event.x;
      d.fy = event.y;
    },

    dragended(event, d) {
      if (!event.active) this.simulation.alphaTarget(0);
      d.fx = null;
      d.fy = null;
    },

    // 显示节点详情
    showNodeDetails(node) {
      this.detailsExpanded = true;
      const detailsContent = this.$refs.detailsContent;

      detailsContent.innerHTML = "";

      // 添加节点基本信息
      const basicInfo = document.createElement("div");
      basicInfo.className = "detail-item";
      basicInfo.innerHTML = `
        <label>节点类型</label>
        <span>${node.label}</span>
      `;
      detailsContent.appendChild(basicInfo);

      const nameInfo = document.createElement("div");
      nameInfo.className = "detail-item";
      nameInfo.innerHTML = `
        <label>显示名称</label>
        <span>${node.name}</span>
      `;
      detailsContent.appendChild(nameInfo);

      // 添加原始数据属性
      if (node.originalData) {
        for (const [key, value] of Object.entries(node.originalData)) {
          if (value !== null && value !== undefined) {
            const detailItem = document.createElement("div");
            detailItem.className = "detail-item";

            const label = document.createElement("label");
            label.textContent = key;

            const span = document.createElement("span");
            span.textContent =
              typeof value === "object" ? JSON.stringify(value) : value;

            detailItem.appendChild(label);
            detailItem.appendChild(span);
            detailsContent.appendChild(detailItem);
          }
        }
      }
    },

    // 切换详情面板
    toggleDetails() {
      this.detailsExpanded = !this.detailsExpanded;
    },

    // 重置视图
    resetView() {
      if (this.simulation) {
        this.simulation.alphaTarget(0.3).restart();
      }
      if (this.svg && this.zoom) {
        this.svg
          .transition()
          .duration(750)
          .call(this.zoom.transform, d3.zoomIdentity);
      }
    },

    // 运行查询（重新加载数据）
    runQuery() {
      this.processData();
    },
  },

  beforeDestroy() {
    // 销毁图表实例
    if (this.simulation) {
      this.simulation.stop();
    }
    // 移除事件监听器
    window.removeEventListener("resize", this.handleResize);
  },
};
</script>

<style scoped>
.neo4j-graph-container {
  width: 100%;
  height: 100%;
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  display: flex;
}

.container {
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 20px;
  height: 100%;
}

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 15px 20px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  backdrop-filter: blur(10px);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}

.logo {
  display: flex;
  align-items: center;
  gap: 10px;
}

.logo-icon {
  font-size: 28px;
  color: #68d391;
}

h1 {
  font-size: 24px;
  font-weight: 600;
  color: #fff;
  margin: 0;
}

.controls {
  display: flex;
  gap: 15px;
}

button {
  padding: 8px 16px;
  border: none;
  border-radius: 5px;
  background: #4fd1c5;
  color: #2d3748;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
}

button:hover {
  background: #38b2ac;
  transform: translateY(-2px);
}

.main-content {
 width: 100%;
 display: flex;
}

.query-info {
  width: 300px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  padding: 20px;
  backdrop-filter: blur(10px);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
  display: flex;
  flex-direction: column;
  gap: 20px;
  overflow-y: auto;
}

.cypher-query {
  background: rgba(0, 0, 0, 0.2);
  padding: 15px;
  border-radius: 8px;
  font-family: monospace;
  font-size: 14px;
  line-height: 1.5;
  overflow-x: auto;
  color: #fff;
}

.legend {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 10px;
}

.legend-color {
  width: 20px;
  height: 20px;
  border-radius: 4px;
}

.node-info {
  margin-top: 20px;
}

.node-info h3 {
  margin-bottom: 10px;
  color: #fff;
}

.node-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.stat-item {
  display: flex;
  flex-direction: column;
  background: rgba(0, 0, 0, 0.2);
  padding: 10px;
  border-radius: 5px;
}

.stat-item label {
  font-size: 12px;
  opacity: 0.8;
  color: #fff;
}

.stat-item span {
  font-size: 16px;
  font-weight: 600;
  color: #fff;
}

.graph-container {
  flex: 1;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  overflow: hidden;
  position: relative;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}

.details-panel {
  position: absolute;
  bottom: 100px;
  left: 20px;
  right: 20px;
  background: rgba(255, 255, 255, 0.15);
  border-radius: 10px;
  padding: 15px;
  backdrop-filter: blur(10px);
  transform: translateY(calc(100% - 50px));
  transition: transform 0.3s ease;
  max-height: 300px;
  overflow-y: auto;
}

.details-panel.expanded {
  transform: translateY(0);
}

.details-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.details-header h3 {
  color: #fff;
  margin: 0;
}

.details-content {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 15px;
}

.detail-item {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.detail-item label {
  font-size: 12px;
  opacity: 0.8;
  color: #fff;
}

.detail-item span {
  font-size: 14px;
  font-weight: 500;
  word-break: break-word;
  color: #fff;
}

.toggle-details {
  background: none;
  color: white;
  font-size: 20px;
  padding: 0;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
}

footer {
  text-align: center;
  padding: 15px;
  font-size: 14px;
  opacity: 0.8;
  color: #fff;
}

h2,
h3 {
  color: #fff;
  margin: 0 0 10px 0;
}

span {
  color: #fff;
}

@media (max-width: 900px) {
  .main-content {
    flex-direction: column;
    height: auto;
  }

  .query-info {
    width: 100%;
  }

  .graph-container {
    height: 500px;
  }
}
</style>
